import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import parser.I3hsParser;
import parser.I3tpParser;
import parser.I3ttpParser;
import parser.Rating;

import util.*;

public class SgxAggregator {

	private HashMap<String, Candle> candles_2;
	private HashMap<String, Candle> candles_1;
	private HashMap<String, Candle> candles_0;
	private HashMap<String, Triplet<Candle, Candle, Candle>> candleTriplets;
	private TreeMap<String, Attributes> filteredCandles;

	public SgxAggregator(String filename_2, String filename_1, String filename_0, String ttpFilename) {
		candles_2 = new HashMap<String, Candle>();
		Util.readFile(filename_2, candles_2);
		candles_1 = new HashMap<String, Candle>();
		Util.readFile(filename_1, candles_1);
		candles_0 = new HashMap<String, Candle>();
		Util.readFile(filename_0, candles_0);
		
		candleTriplets = Util.matchCandleTriplets(candles_2, candles_1, candles_0);

		Collection<Triplet<Candle, Candle, Candle>> tripletsCollection = candleTriplets.values();
		List tripletsList = new ArrayList<Triplet<Candle, Candle, Candle>>(tripletsCollection);
		Collections.sort(tripletsList, new ValueComparable());
		Iterator<Triplet<Candle, Candle, Candle>> iterRankedByValue = tripletsList.iterator();
		int rank = 1;
		while (iterRankedByValue.hasNext()) {
			Triplet<Candle, Candle, Candle> triplet = iterRankedByValue.next();
			Candle candle_0 = triplet.getC();
			candle_0.setValueRank(rank);
			rank++;
		}

		tripletsList = new ArrayList<Triplet<Candle, Candle, Candle>>(tripletsCollection);
		Collections.sort(tripletsList, new VolumeComparable());
		Iterator<Triplet<Candle, Candle, Candle>> iterRankedByVolume = tripletsList.iterator();
		rank = 1;
		while (iterRankedByVolume.hasNext()) {
			Triplet<Candle, Candle, Candle> triplet = iterRankedByVolume.next();
			Candle candle_0 = triplet.getC();
			candle_0.setVolumeRank(rank);
			rank++;
		}

		I3ttpParser i3ttpParser = new I3ttpParser(ttpFilename);
		I3tpParser i3tpParser = new I3tpParser();
		I3hsParser i3hsParser = new I3hsParser(filename_0);
		
		filteredCandles = new TreeMap<String, Attributes>();
		Iterator<String> iter = candleTriplets.keySet().iterator();
		while (iter.hasNext()) {
			String stockName = iter.next();
			Triplet<Candle, Candle, Candle> candles = candleTriplets.get(stockName);
			Candle candle_2 = candles.getA();
			Candle candle_1 = candles.getB();
			Candle candle_0 = candles.getC();

			Rating rating = i3ttpParser.getRating(stockName);
	      float tp = i3tpParser.getTargetPrice(stockName);
	      int hottness = i3hsParser.getHottness(stockName);
	      boolean isReitOrTrust = Util.isReitOrTrust(stockName);
		      
			float engulfingRatio = candle_1.getEngulfingRatio(candle_0); 
			if (engulfingRatio >= 3) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setEngulfingRatio(engulfingRatio);
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			if (candle_0.isBlack() && candle_1.isBlack() && candle_2.isBlack()) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setIs3BlackSoldiers();
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			if (candle_2.getWilliamsR(candle_1, candle_0) > 0.8) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setOversold(candle_2.getWilliamsR(candle_1, candle_0));
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			if (candle_0.isDoji(candle_1)) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setDoji(true);
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			float hammerRatio = candle_0.getHammerRatio(candle_1); 
			if (hammerRatio >= 3) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setHammerRatio(hammerRatio);
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			int numTicks = candle_2.isSupported(2, candle_1, candle_0);
			if (numTicks >= 5) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setSupportedTicks(numTicks);
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			if (candle_2.isPriceLowReversed(candle_1, candle_0)) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setPriceLowReversed();
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}

			if (candle_2.is2White(candle_1, candle_0)) {
				Attributes attributes = filteredCandles.get(stockName);
				if (attributes == null) attributes = new Attributes(stockName);
				attributes.setIs2WhiteSoldiers();
				attributes.setValueRank(candle_0.getValueRank());
				attributes.setVolumeRank(candle_0.getVolumeRank());
				attributes.setReitOrTrust(isReitOrTrust);
				attributes.setRating(rating);
				attributes.setTargetPrice(tp);
				attributes.setHottness(hottness);
				filteredCandles.put(stockName, attributes);
			}
		}
		
		Collection<Attributes> filteredCandlesCollection = filteredCandles.values();
		ArrayList<Attributes> filteredCandlesList = new ArrayList<Attributes>(filteredCandlesCollection);
		Collections.sort(filteredCandlesList, new RankComparable());

		String paddedStock = String.format("%1$-30s", "stock");
	      DecimalFormat formatter = new DecimalFormat("#.#");
		System.out.println(paddedStock + "\t" + "RT" + "\t" + "TTP" + "\t" + "TP" + "\t" + "HS" + "\t" + "ER" + "\t" + "3B" + "\t" + "%R" + "\t" + "DR" + "\t" + "HR" + "\t" + "Sup" + "\t" + "Rev" + "\t" + "2W" + "\t" + "Val" + "\t" + "Vol");
		Iterator<Attributes> rankedIter = filteredCandlesList.iterator();
		while (rankedIter.hasNext()) {
			Attributes attributes = rankedIter.next();
			String stockName = attributes.getStockName();
			String paddedStockName = String.format("%1$-30s", attributes.getStockName());
			String er = formatter.format(attributes.getEngulfingRatio());
			er = er.equals("0") ? "" : er;
			String hr = formatter.format(attributes.getHammerRatio());
			hr = hr.equals("0") ? "" : hr;
			String sup = formatter.format(attributes.getSupportedTicks());
			sup = sup.equals("0") ? "" : sup;
			String b3 = attributes.isIs3BlackSoldiers()? "Y" : "";
			String dr = attributes.isDoji()? "Y" : "";
			String rev = attributes.isPriceLowReversed()? "Y" : "";
			String is2W = attributes.isIs2WhiteSoldiers()? "Y" : "";
			String isRT = attributes.isReitOrTrust()? "Y" : "";
			int valR = attributes.getValueRank();
			int volR = attributes.getVolumeRank();
			String volRstr = volR == 0 ? "" : volR + "";
		      Rating rating = attributes.getRating();
		      String ratingString = rating == null? "" : rating.toString();
		      float tp = attributes.getTargetPrice();
		      String tpString = tp < 0? "" : tp + "";
		      int hottness = attributes.getHottness();
		      String hsString = hottness < 0? "" : hottness + "";
		      float oversold = attributes.getOversold();
		      String osString = oversold < 0.8? "" : formatter.format(oversold);
			System.out.println(paddedStockName + "\t" + isRT + "\t" + ratingString + "\t" + tpString + "\t" + hsString + "\t" + er + "\t" + b3 + "\t" + osString + "\t" + dr + "\t" + hr + "\t" + sup + "\t" + rev + "\t" + is2W + "\t" + valR + "\t" + volRstr);
		}
	}
	
	public static void main(String[] args) {
		new SgxAggregator(args[0], args[1], args[2], args[3]);
	}

}
